﻿
// 段选择子Dlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "段选择子.h"
#include "段选择子Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// C段选择子Dlg 对话框



C段选择子Dlg::C段选择子Dlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MY_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void C段选择子Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT1, EDIT_DXZZ);
	DDX_Control(pDX, IDC_EDIT2, EDIT_GDT_LDT);
	DDX_Control(pDX, IDC_EDIT3, EDIT_SY);
	DDX_Control(pDX, IDC_EDIT4, EDIT_TI);
	DDX_Control(pDX, IDC_EDIT5, EDIT_RPL);
	DDX_Control(pDX, IDC_EDIT6, EDIT_DMSF);
	DDX_Control(pDX, IDC_EDIT13, EDIT_BASE);
	DDX_Control(pDX, IDC_EDIT8, EDIT_LIMIT);
	DDX_Control(pDX, IDC_EDIT9, EDIT_TYPE);
	DDX_Control(pDX, IDC_EDIT15, EDIT_S);
	DDX_Control(pDX, IDC_EDIT18, EDIT_DPL);
	DDX_Control(pDX, IDC_EDIT10, EDIT_P);
	DDX_Control(pDX, IDC_EDIT14, EDIT_AVL);
	DDX_Control(pDX, IDC_EDIT12, EDIT_G);
	DDX_Control(pDX, IDC_EDIT7, EDIT_DMSFADD);
	DDX_Control(pDX, IDC_EDIT11, EDIT_DB);
}

BEGIN_MESSAGE_MAP(C段选择子Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &C段选择子Dlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &C段选择子Dlg::OnBnClickedButton2)
END_MESSAGE_MAP()


// C段选择子Dlg 消息处理程序

BOOL C段选择子Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void C段选择子Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void C段选择子Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR C段选择子Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void C段选择子Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码

// 🔸 第1步：获取并验证段选择子输入
	CString strSelector;                                    // 创建字符串变量存储段选择子输入
	EDIT_DXZZ.GetWindowText(strSelector);                  // 从段选择子编辑框获取用户输入
	strSelector.Trim();                                     // 去除字符串首尾的空格字符

	// 检查输入是否为空
	if (strSelector.IsEmpty())                              // 如果输入为空字符串
	{
		MessageBox(_T("请输入段选择子！"), _T("错误"), MB_ICONERROR);  // 显示错误提示消息
		return;                                             // 退出函数，不执行后续代码
	}

	// 🔸 第2步：解析段选择子为数值
	DWORD selector = 0;                                     // 初始化段选择子数值变量
	try                                                     // 开始异常处理块
	{
		// 检查输入是否以"0x"开头（十六进制前缀）
		if (strSelector.Left(2).CompareNoCase(_T("0x")) == 0)  // 如果前两个字符是"0x"（忽略大小写）
		{
			// 跳过"0x"前缀，从第3个字符开始解析十六进制数
			selector = (DWORD)_tcstoull(strSelector.Mid(2), nullptr, 16);
		}
		else                                                // 如果没有"0x"前缀
		{
			// 直接解析整个字符串为十六进制数
			selector = (DWORD)_tcstoull(strSelector, nullptr, 16);
		}
	}
	catch (...)                                            // 捕获任何异常
	{
		MessageBox(_T("段选择子格式错误！"), _T("错误"), MB_ICONERROR);  // 显示格式错误提示
		return;                                            // 退出函数
	}

	// 🔸 第3步：提取段选择子各个字段
	// 段选择子结构：15-3位(索引) | 2位(TI) | 1-0位(RPL)
	DWORD index = (selector >> 3) & 0x1FFF;               // 右移3位后与0x1FFF相与，提取索引字段(13位)
	DWORD ti = (selector >> 2) & 0x1;                     // 右移2位后与0x1相与，提取TI位(表指示符)
	DWORD rpl = selector & 0x3;                           // 与0x3相与，提取RPL字段(请求特权级，2位)

	// 🔸 第4步：显示基本解析结果
	CString strTemp;                                       // 创建临时字符串变量用于格式化

	// 显示索引值
	strTemp.Format(_T("%d"), index);                       // 将索引格式化为十进制字符串
	EDIT_SY.SetWindowText(strTemp);                        // 在索引编辑框中显示结果

	// 显示TI位和对应的表类型
	if (ti)                                                // 如果TI位为1
	{
		strTemp.Format(_T("%d(LDT)"), ti);                 // 格式化为"1(LDT)"，表示使用LDT表
		EDIT_TI.SetWindowText(strTemp);                     // 在TI编辑框中显示结果
	}
	else                                                   // 如果TI位为0
	{
		strTemp.Format(_T("%d(GDT)"), ti);                 // 格式化为"0(GDT)"，表示使用GDT表
		EDIT_TI.SetWindowText(strTemp);                     // 在TI编辑框中显示结果
	}

	// 显示RPL值
	strTemp.Format(_T("%d"), rpl);                         // 将RPL格式化为十进制字符串
	EDIT_RPL.SetWindowText(strTemp);                       // 在RPL编辑框中显示结果

	// 🔸 第5步：处理GDT/LDT表地址输入
	CString strTableAddr;                                  // 创建字符串变量存储表地址输入
	EDIT_GDT_LDT.GetWindowText(strTableAddr);             // 从表地址编辑框获取用户输入
	strTableAddr.Trim();                                   // 去除字符串首尾空格

	// 清空段描述符地址显示
	EDIT_DMSFADD.SetWindowText(_T(""));                    // 清空段描述符地址编辑框的内容

	// 🔸 第6步：计算段描述符地址
	// 只有当输入了表地址时才计算段描述符地址
	if (!strTableAddr.IsEmpty())                           // 如果表地址输入不为空
	{
		try                                                // 开始异常处理块
		{
			ULONGLONG tableBaseAddr = 0;                   // 初始化表基地址变量（64位）

			// ✅ 解析表地址
			if (strTableAddr.Left(2).CompareNoCase(_T("0x")) == 0)  // 如果输入以"0x"开头
			{
				// 注意：这里应该是Mid(2)而不是Mid(8)，跳过"0x"前缀
				tableBaseAddr = _tcstoull(strTableAddr.Mid(2), nullptr, 16);
			}
			else                                           // 如果没有"0x"前缀
			{
				// 直接解析整个字符串为十六进制数
				tableBaseAddr = _tcstoull(strTableAddr, nullptr, 16);
			}

			// 计算段描述符地址：表基址 + (索引 × 8)
			// 每个段描述符占8字节，所以索引要乘以8
			ULONGLONG descriptorAddr = tableBaseAddr + (static_cast<ULONGLONG>(index) * 8);

			// 🔸 第7步：格式化显示段描述符地址
			CString strDescriptorAddr;                     // 创建字符串变量存储格式化后的地址
			if (descriptorAddr <= 0xFFFFFFFFUL)            // 如果地址在32位范围内
			{
				// 使用32位格式显示（8位十六进制）
				strDescriptorAddr.Format(_T("0x%08X"), static_cast<DWORD>(descriptorAddr));
			}
			else                                           // 如果地址超出32位范围
			{
				// 使用64位格式显示（16位十六进制）
				strDescriptorAddr.Format(_T("0x%016I64X"), descriptorAddr);
			}

			// 显示计算结果
			EDIT_DMSFADD.SetWindowText(strDescriptorAddr); // 在段描述符地址编辑框中显示结果

		}
		catch (...)                                        // 捕获解析过程中的任何异常
		{
			MessageBox(_T("表地址格式错误！请输入有效的数值"), _T("错误"), MB_ICONERROR);  // 显示错误提示
			EDIT_GDT_LDT.SetFocus();                       // 将焦点设置回表地址输入框
		}
	}
}

void C段选择子Dlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码

	// 🔸 第1步：获取并清理输入
	CString strInput;                           // 创建字符串变量存储用户输入
	EDIT_DMSF.GetWindowText(strInput);         // 从编辑框获取用户输入的文本
	strInput.Trim();                           // 去除字符串首尾空格
	strInput.MakeUpper();                      // 将所有字符转换为大写

	// 移除所有非十六进制字符
	CString cleanHex;                          // 创建新字符串存储清理后的十六进制字符
	for (int i = 0; i < strInput.GetLength(); i++)  // 遍历输入字符串的每个字符
	{
		TCHAR ch = strInput[i];                // 获取当前字符
		// 检查字符是否为有效的十六进制字符(0-9, A-F)
		if ((ch >= _T('0') && ch <= _T('9')) || (ch >= _T('A') && ch <= _T('F')))
		{
			cleanHex += ch;                    // 如果是有效字符，添加到清理后的字符串
		}
	}

	// 🔸 第2步：验证输入长度
	if (cleanHex.GetLength() != 16)            // 检查清理后的字符串是否正好16个字符
	{
		// 如果长度不对，显示错误消息框并退出函数
		MessageBox(_T("请输入16个十六进制数字！"), _T("输入错误"), MB_ICONERROR);
		return;
	}

	// 🔸 第3步：转换为64位整数
	UINT64 descriptor = 0;                     // 初始化64位整数变量存储段描述符
	for (int i = 0; i < 16; i++)              // 遍历16个十六进制字符
	{
		TCHAR ch = cleanHex[i];                // 获取当前字符
		// 将十六进制字符转换为数字值：0-9转换为0-9，A-F转换为10-15
		int digit = (ch >= _T('0') && ch <= _T('9')) ? (ch - _T('0')) : (ch - _T('A') + 10);
		descriptor = (descriptor << 4) | digit; // 左移4位并添加新的4位数字
	}

	// 🔸 第4步：解析段描述符各字段
	// 段描述符结构：
	// 63-56: Base[31:24]  55: G  54: D/B  53: L  52: AVL  51-48: Limit[19:16]
	// 47-40: Access Byte  39-16: Base[23:0]  15-0: Limit[15:0]

	// 基地址 = [39:16] + [63:56]
	// 提取位16-39的24位基地址低位，与位56-63的8位基地址高位组合
	DWORD baseAddr = (DWORD)(((descriptor >> 16) & 0xFFFFFF) |
		(((descriptor >> 56) & 0xFF) << 24));

	// 段界限 = [15:0] + [51:48]
	// 提取位0-15的16位段界限低位，与位48-51的4位段界限高位组合
	DWORD segLimit = (DWORD)((descriptor & 0xFFFF) |
		(((descriptor >> 48) & 0xF) << 16));

	// 访问权限字节 [47:40]
	BYTE accessByte = (BYTE)((descriptor >> 40) & 0xFF);  // 提取8位访问权限字节
	BYTE type = accessByte & 0x0F;                        // 提取位0-3：段类型
	BYTE s = (accessByte >> 4) & 0x01;                    // 提取位4：S位(系统/用户段标志)
	BYTE dpl = (accessByte >> 5) & 0x03;                  // 提取位5-6：DPL(描述符特权级)
	BYTE p = (accessByte >> 7) & 0x01;                    // 提取位7：P位(存在标志)

	// 其他标志位
	BYTE avl = (BYTE)((descriptor >> 52) & 0x01);         // 提取位52：AVL位(可用位)
	BYTE l = (BYTE)((descriptor >> 53) & 0x01);           // 提取位53：L位(64位代码段标志)
	BYTE db = (BYTE)((descriptor >> 54) & 0x01);          // 提取位54：D/B位(操作数大小/栈指针大小)
	BYTE g = (BYTE)((descriptor >> 55) & 0x01);           // 提取位55：G位(粒度标志)

	// 🔸 第5步：显示解析结果
	CString str;                                          // 创建字符串变量用于格式化输出

	// 基地址
	str.Format(_T("0x%08X"), baseAddr);                   // 格式化基地址为8位十六进制
	EDIT_BASE.SetWindowText(str);                         // 在基地址编辑框中显示结果

	// 段界限（考虑G位）
	if (g == 1) {                                         // 如果G位为1，使用4KB粒度
		str.Format(_T("0x%X (4KB单位)"), segLimit);
	}
	else {                                              // 如果G位为0，使用字节粒度
		str.Format(_T("0x%X (字节单位)"), segLimit);
	}
	EDIT_LIMIT.SetWindowText(str);                        // 在段界限编辑框中显示结果

	// 段类型
	CString typeDesc;                                     // 创建字符串存储段类型描述
	if (s == 0) {                                        // S位为0表示系统段
		switch (type) {                                   // 根据type值判断系统段类型
		case 0x1: typeDesc = _T("16位TSS(可用)"); break;
		case 0x2: typeDesc = _T("LDT"); break;
		case 0x3: typeDesc = _T("16位TSS(忙)"); break;
		case 0x9: typeDesc = _T("32位TSS(可用)"); break;
		case 0xB: typeDesc = _T("32位TSS(忙)"); break;
		default:  typeDesc = _T("系统段"); break;
		}
	}
	else {                                             // S位为1表示用户段
		if (type & 0x8) {                               // 检查type的第3位判断是否为代码段
			typeDesc = _T("代码段");
		}
		else {
			typeDesc = _T("数据段");
		}
	}
	str.Format(_T("0x%X (%s)"), type, typeDesc);        // 格式化段类型和描述
	EDIT_TYPE.SetWindowText(str);                        // 在段类型编辑框中显示结果

	// S位
	str.Format(_T("%d (%s)"), s, s ? _T("代码/数据段(软件使用)") : _T("系统段(硬件使用)"));// 格式化S位值和描述
	EDIT_S.SetWindowText(str);// 在S位编辑框中显示结果

	// DPL特权级
	str.Format(_T("%d (Ring %d)"), dpl, dpl);           // 格式化DPL值和Ring级别
	EDIT_DPL.SetWindowText(str);                         // 在DPL编辑框中显示结果

	// P位存在标志
	str.Format(_T("%d (%s)"), p, p ? _T("存在") : _T("不存在"));  // 格式化P位值和状态描述
	EDIT_P.SetWindowText(str);                           // 在P位编辑框中显示结果

	// AVL可用位
	str.Format(_T("%d"), avl);                           // 格式化AVL位值
	EDIT_AVL.SetWindowText(str);                         // 在AVL编辑框中显示结果

	// 🔸 新增：D/B位解析和显示
	CString dbDesc;                                      // 创建字符串存储D/B位详细描述
	if (s == 1) {                                       // 如果是用户段
		if (type & 0x08) {                              // 如果是代码段
			// 代码段 - D位（默认操作数大小）
			if (l == 1) {                               // 如果是64位代码段
				// 64位代码段
				dbDesc.Format(_T("%d - 64位代码段\nD位在64位模式下被忽略"), db);
			}
			else {                                    // 如果是32位或16位代码段
				// 32位或16位代码段
				dbDesc.Format(_T("%d - D位（默认操作数大小）\n%s位代码段\n默认%s位操作数/地址"),
					db, db ? _T("32") : _T("16"), db ? _T("32") : _T("16"));
			}
		}
		else {                                        // 如果是数据段
			// 数据段 - B位（栈指针大小）
			dbDesc.Format(_T("%d - B位（栈段属性）\n%s位栈段\n使用%s栈指针"),
				db, db ? _T("32") : _T("16"), db ? _T("ESP") : _T("SP"));
		}
	}
	else {                                            // 如果是系统段
		// 系统段
		dbDesc.Format(_T("%d - 系统段保留位\n在系统段中此位为保留"), db);
	}
	EDIT_DB.SetWindowText(dbDesc);                       // 在D/B位编辑框中显示详细描述

	// G粒度位
	str.Format(_T("%d (%s)"), g, g ? _T("4KB粒度") : _T("字节粒度"));  // 格式化G位值和粒度描述
	EDIT_G.SetWindowText(str);                           // 在G位编辑框中显示结果
}
